/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file Writer.cpp
 * @author suzuki ryoutoku
 */
//=============================================================================
//	pre processor
//=============================================================================

#include "Writer.h"
#include <fstream>
using namespace library::graphics;


//=============================================================================
//	Writer's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-6-23
 */
Writer::Writer(const char* filename)
{
  if( filename != NULL ) strcpy( m_filename, filename);
}


/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-6-23
 */
bool Writer::outputPCM(library::graphics::Model* model)
{
  ofstream fout;
  fout.open(m_filename);
  fout << "* This file is created by StripExperiment" << endl;
  fout << model->get_vertex_sum() << " " 
	   << "0 "
	   << model->getPolygonBodySum() << endl;

  // Writing vertex
  for( int i = 0; i < model->getPolygonBodySum(); i ++ ){
	library::graphics::PolygonBody* body = model->getPolygonBody(i);
	for( int j = 0; j  < body->get_vertex_sum(); j++ ){
	  Vector<double> ver = body->get_vertex(j);
	  fout << ver.x << " " 
		   << ver.y << " " 
		   << ver.z << endl;
	}
  }
  
  // Writing polygon
  int before_vertex_sum = 0;
  for( int i = 0; i < model->getPolygonBodySum(); i ++ ){
	library::graphics::PolygonBody* body = model->getPolygonBody(i);
	fout << body->getFaceSum() << " 0 0" << endl;
	for( int j = 0; j < body->getFaceSum(); j++ ){
	  library::graphics::Polygon* poly = body->get_face(j);
	  switch( poly->get_type() ){
	  case 3:
		{
		  fout << before_vertex_sum + poly->get_connectivity_pointer()[0] 
			   << " "
			   << before_vertex_sum + poly->get_connectivity_pointer()[2] 
			   << " "
			   << before_vertex_sum + poly->get_connectivity_pointer()[1] 
			   << " "
			   << endl;
		}
		break;
	  case 4:
		{
		  fout << before_vertex_sum + poly->get_connectivity_pointer()[0] 
			   << " "
			   << before_vertex_sum + poly->get_connectivity_pointer()[3] 
			   << " "
			   << before_vertex_sum + poly->get_connectivity_pointer()[2] 
			   << " "
			   << before_vertex_sum + poly->get_connectivity_pointer()[1] 
			   << " "
			   << endl;
		}
		break;
	  }
	}
	before_vertex_sum += body->get_vertex_sum();
  }
  fout.close();
  return true;
}

/**
 * This method is to create a text file with vdf format.
 * @author r-suzuki
 * @date 2008-12-7
 * @version 1.0
 */
bool Writer::outputVDF(library::graphics::Model* model)
{
  ofstream fout;
  fout.open(m_filename);
  fout << "# This file is created by StripExperiment" << endl;
  fout << "# vertex sum = " << model->get_vertex_sum() << endl;
  fout << "# body sum = " << model->getPolygonBodySum() << endl;
  

  for( int i = 0; i < model->getPolygonBodySum(); i ++ ){
	library::graphics::PolygonBody* body = model->getPolygonBody(i);	

	if( this->outputPolygonBody(fout, body, i) == false){
	  cout << "Error output body" << endl;
	  return false;
	}
	if( this->outputVertex(fout, body, i) == false){
	  cout << "Error output vertex" << endl;
	  return false;
	}

	if( this->outputUV(fout, body, i) == false){
	  cout << "Error output uv" << endl;
	  return false;
	}
	
	if( this->outputCluster(fout, body, i) == false){
	  cout << "Error output cluster" << endl;
	  return false;
	}

	if( this->outputTextureGroup(fout, body, i) == false){
	  cout << "Error output texture group" << endl;
	  return false;
	}

	if( this->outputSelectionGroup(fout, body, i) == false){
	  cout << "Error output selection group" << endl;
	  return false;
	}

  }

  fout.close();
  return true;
}


/**
 * Writing body
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool 
library::graphics::Writer::outputPolygonBody(ofstream& fout, 
											 library::graphics::PolygonBody* body, 
											 int id)
{
  fout << "#################################################\n";
  fout << "$PolygonBody" << endl;
  fout << "#################################################\n";
  fout << "id=" << id << endl;
  fout << "name=" << body->get_name() << endl;
  fout << "sum=" << body->getFaceSum() << endl;
  
  for( int j = 0; j  < body->getFaceSum(); j++ ){
	library::graphics::Polygon* poly = body->get_face(j);
	fout << "\t" << poly->get_global_id()<< " " << poly->get_type() << endl;
  }

  return true;
}

/**
 * Writing vertex
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::Writer::outputVertex(ofstream& fout,
											 library::graphics::PolygonBody* body,
											 int targetid)
{
  fout << "#################################################\n";
  fout << "$NodalCoordinate" << endl;
  fout << "#################################################\n";
  fout << "target_id=" << targetid << endl;
  fout << "sum=" << body->get_vertex_sum() << endl;
	  
  for( int j = 0; j  < body->get_vertex_sum(); j++ ){
	Vector<double> ver = body->get_vertex(j);
	fout << "\t" << body->get_vertex_id(j) << " "
		 << ver.x << " "
		 << ver.y << " "
		 << ver.z << endl;
  }
  return true;
}

/**
 * Writing uv
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::Writer::outputUV(ofstream& fout,
										 library::graphics::PolygonBody* body,
										 int targetid)
{
  if( false == body->isUV() )	return true;
  fout << "#################################################\n";
  fout << "$UV" << endl;
  fout << "#################################################\n";
  fout << "target_id=" << targetid << endl;
  fout << "sum=" << body->get_vertex_sum() << endl;
  
  for( int j = 0; j  < body->get_vertex_sum(); j++ ){
	Vector2D<float> uv = body->get_uv(j);
	fout << "\t" << body->get_vertex_id(j) << " "
		 << uv.u << " "
		 << uv.v << endl;
  }

  return true;
}



/**
 * Writing cluster
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::Writer::outputCluster(ofstream& fout,
											  library::graphics::PolygonBody* body,
											  int targetid)
{
  for( int j = 0; j < body->getClusterSum();j++ ){
	library::graphics::Cluster* cluster = body->get_cluster(j);
	fout << "#################################################\n";
	switch( cluster->get_type() ){
	case library::graphics::Cluster::TRIANGLE_CLUSTER:
	  fout << "$TriangleCluster" << endl;
	  break;
	case library::graphics::Cluster::RECTANGLE_CLUSTER:
	  fout << "$RectangleCluster" << endl;
	  break;
	case library::graphics::Cluster::STRIP_CLUSTER:
	  fout << "$StripCluster" << endl;
	  break;
	}
	fout << "#################################################\n";
	fout << "id=" << j << endl;
	fout << "target_id=" << targetid << endl;
	fout << "sum=" << cluster->get_sum() << endl;
	for( int k = 0; k < cluster->get_sum(); k++ ){
	  fout << "\t";
	  switch( cluster->get_type() ){
	  case library::graphics::Cluster::TRIANGLE_CLUSTER:
		fout << cluster->get_polygon_id(k) << " ";
		fout << cluster->get_connectivity(k)[0] << " "
			 << cluster->get_connectivity(k)[1] << " "
			 << cluster->get_connectivity(k)[2] << endl;
		break;
	  case library::graphics::Cluster::RECTANGLE_CLUSTER:
		fout << cluster->get_polygon_id(k) << " ";
		fout << cluster->get_connectivity(k)[0] << " "
			 << cluster->get_connectivity(k)[1] << " "
			 << cluster->get_connectivity(k)[2] << " "
			 << cluster->get_connectivity(k)[3] << endl;
		break;
	  case library::graphics::Cluster::STRIP_CLUSTER:
		if( k == 0 ){
		  fout << cluster->get_connectivity(k)[0] << " "
			   << cluster->get_connectivity(k)[1] << endl;
		}else{
		  fout << cluster->get_connectivity(k)[0] << endl;
		}
		
		break;
	  }
	}
  }
  return true;
}


/**
 * Writing texture group.
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool 
library::graphics::Writer::outputTextureGroup(ofstream& fout,
											  library::graphics::PolygonBody* body,
											  int targetid)
{
  int groupsum = body->querySpecificGroupSum(Group::TEXTURE, Group::CLUSTER);
  for(int j=0; j < groupsum; j++){
	Group* group = body->queryGroup(Group::TEXTURE, Group::CLUSTER, j);
	fout << "#################################################\n";
	fout << "$Group\n";
	fout << "#################################################\n";
	fout << "type=" << Group::TEXTURE << endl;
	fout << "target_type=" << Group::CLUSTER << endl;
	fout << "name=" << group->get_name() << endl;
	if( group->get_texid() != -1 ){
	  fout << "dataname=" << group->get_texname() << endl;
	}
	fout << "sum=" << group->getTargetSum() << endl;
	for( int k = 0; k < group->getTargetSum(); k++ ){
	  fout << "\t" << *(group->getTarget(k)) << endl;
	}
  }
  return true;
}

/**
 *
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool 
library::graphics::Writer::outputSelectionGroup(ofstream& fout,
												library::graphics::PolygonBody* body,
												int targetid)
{
  int groupsum = body->querySpecificGroupSum(Group::SELECTION, Group::VERTEX);
  for(int j=0; j < groupsum; j++){
	Group* group = body->queryGroup(Group::SELECTION, Group::VERTEX, j);
	if( group->getTargetSum() == 0 ) continue;
	fout << "#################################################\n";
	fout << "$Group\n";
	fout << "#################################################\n";
	fout << "type=" << Group::SELECTION << endl;
	fout << "target_type=" << Group::VERTEX << endl;
	fout << "name=" << group->get_name() << endl;
	fout << "sum=" << group->getTargetSum() << endl;
	for( int k = 0; k < group->getTargetSum(); k++ ){
	  fout << "\t" << *(group->getTarget(k)) << endl;
	}
  }
  groupsum = body->querySpecificGroupSum(Group::SELECTION, Group::POLYGON);
  for(int j=0; j < groupsum; j++){
	Group* group = body->queryGroup(Group::SELECTION, Group::POLYGON, j);
	if( group->getTargetSum() == 0 ) continue;
	fout << "#################################################\n";
	fout << "$Group\n";
	fout << "#################################################\n";
	fout << "type=" << Group::SELECTION << endl;
	fout << "target_type=" << Group::POLYGON << endl;
	fout << "name=" << group->get_name() << endl;
	fout << "sum=" << group->getTargetSum() << endl;
	for( int k = 0; k < group->getTargetSum(); k++ ){
	  fout << "\t" << *(group->getTarget(k)) << endl;
	}
  }
  return true;
}
